package com.sk.ccflower.lib.util.json;

import java.io.IOException;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.Writer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * <p>Java 객체를 JSON으로 변환하거나, JSON을 Java객체로 변환하는데 사용되는 여러 자료형의 추상 클래스.</p>
 * @author         dagui
 */
public abstract class JSONObject implements JSONCompatible, Serializable {

	private static final long serialVersionUID = 3308423587381423408L;
	
	private static final Log log = LogFactory.getLog(JSONObject.class);
	
	/**
	 * JSON의 'null' 을 표현하는 객체, Java의 null과 호환된다.
	 */
	public static final JSONObject NULL = new JSONObject() {
		private static final long serialVersionUID = 6322323895343326850L;

		@Override
		public void writeJSON(Writer out) throws IOException {
			out.write("null");
		}

		@Override
		public Object getValue() {
			return null;
		}
	};

	/**
	 * 지정한 Writer 에 자신의 내용을 JSON 형식으로 기록한다.
	 * @param out 출력 대상 Writer
	 * @throws IOException 쓰는 중 예외 발생시
	 */
	public abstract void writeJSON(Writer out) throws IOException;

	/**
	 * 객체가 표현하는 Java 자료형을 리턴한다.
	 */
	public abstract Object getValue();

	/**
	 * 객체 내용을 JSON 표기로 변환해서 리턴한다.
	 */
	public String toJSON() {
		StringWriter buf = new StringWriter();
		try {
			writeJSON(buf);
		}
		catch (IOException e) { }
		return buf.toString();
	}

	/**
	 * 문자열로 변환한다.
	 * {@link #toJSON()}과 같은 값을 리턴한다.
	 */
	@Override
	public String toString() {
		return toJSON();
	}

	/**
	 * 해시코드를 계산한다.
	 * {@link #getValue()}.hashCode()와 같은 값을 리턴한다.
	 */
	@Override
	public int hashCode() {
		Object value = getValue();
		return (value == null)? 0: value.hashCode();
	}
	
	/**
	 * 지정한 객체와 같은지 여부를 리턴한다.
	 * 비교 대상 객체가 JSONObject인 경우 {@link #getValue()}를 이용해서 비교한다.
	 */
	@Override
	public boolean equals(Object o) {
		if (o == null)
			return false;
		else if (this == o)
			return true;
		else if (getClass() != o.getClass())
			return false;

		Object value = getValue();
		JSONObject j = (JSONObject)o;
		return (value == null)? j.getValue() == null: value.equals(j.getValue());
	}

//	/**
//	 * Java 객체를 {@link JSONCompatible} 로 변환한다.
//	 * @param o 임의의 Java 객체
//	 * @return JSONCompatible 객체
//	 */
//	@SuppressWarnings({ "rawtypes" })
//	public static JSONCompatible getJSONCompatible(Object o) {
//
//		if (o == null) {
//			return NULL;
//		}
//		else if (o instanceof JSONCompatible) {
//			return (JSONCompatible)o;
//		}
//		else if (o instanceof Boolean) {
//			return JSONBoolean.getJSONBoolean((Boolean)o);
//		}
//		else if (o instanceof Number) {
//			return new JSONNumber((Number)o);
//		}
//		else if (o instanceof String) {
//			return new JSONString((String)o);
//		}
//		else if (o instanceof Date) {
//			DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//			return new JSONString(df.format(o));
//		}
//		else if (o.getClass().isArray()) {
//			return new JSONArray(o);
//		}
//		else if (o instanceof Map) {
//			return new JSONMap((Map)o);
//		}
//		else if (o instanceof Collection) {
//			return new JSONCollection((Collection)o);
//		}
//		else {
//			JSONWrapper wrapper = JSONWrapper.getInstance(o);
////			if (log.isDebugEnabled()) {
////				log.debug(o.getClass() + ": wrapper class is " + wrapper.getClass());
////			}
//			return wrapper;
//		}
//	}

}
